package lerry.nape.body;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.geom.Matrix;
import lerry.nape.utils.DisplayObjectISO;
import nape.geom.AABB;
import nape.geom.GeomPoly;
import nape.geom.GeomPolyList;
import nape.geom.MarchingSquares;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.BodyType;
import nape.phys.Compound;
import nape.shape.Polygon;
import nape.space.Space;
	
	
/**
 * ...
 * @author lxq
 */
class Terrain{
	 var bitmap:Bitmap;
	 var data:BitmapData;
	 
		
	 var cellSize:Float;
	 var subSize:Float;
		
	 var width:Int;
	 var height:Int;
	 var cells:Array<Body>;
	 
	 var cellBounds:AABB;
	 var compound:Compound;
		
	 var cellGranularity:Vec2;
	 var quality:Int = 8;
	 
	 var iso:DisplayObjectISO;
	 
	 public function new(bitmapdata:BitmapData,cellSize:Float=30,subSize:Float=10,space:Space=null){
		this.data=bitmapdata;
		this.cellSize=cellSize;
		this.subSize = subSize;
		
			
		compound=new Compound();
		if(space!=null)compound.space=space;
		cells = [];
		width=Math.ceil(bitmapdata.width / cellSize);
		height = Math.ceil(bitmapdata.height / cellSize);
		
		for(i in 0...width * height) {
			cells.push(null);
		}
			
		cellBounds=new AABB(0,0,cellSize,cellSize);
		cellGranularity=Vec2.get(subSize,subSize);
		
		
		bitmap = new Bitmap(data);
		iso = new DisplayObjectISO(bitmap);
	}
	public function create():Void {
		var x0 = Std.int(iso.bounds.min.x/cellSize); if(x0<0) x0 = 0;
        var y0 = Std.int(iso.bounds.min.y/cellSize); if(y0<0) y0 = 0;
        var x1 = Std.int(iso.bounds.max.x/cellSize); if(x1>= width) x1 = width-1;
        var y1 = Std.int(iso.bounds.max.y/cellSize); if(y1>=height) y1 = height-1;
		var x:UInt, y:UInt;
		for(y in y0...(y1+1)) {
			for(x in x0...(x1+1)) {
				var b:Body=cells[y * width + x];
				if(b != null) {
					b.compound=null;
					b.shapes.clear();
				} else {
					cells[y * width + x]=b=new Body(BodyType.STATIC);
				}
				cellBounds.x=x * cellSize;
				cellBounds.y = y * cellSize;
				var polys:GeomPolyList;
				#if (flash)
				polys=MarchingSquares.run(iso,cellBounds,cellGranularity,quality);
				#else
				polys=MarchingSquares.run(iso.iso,cellBounds,cellGranularity,quality);
				#end
				
				if(polys.empty())
					continue;
				polys.foreach(function(p:GeomPoly):Void {
					var geom:GeomPolyList=p.convexDecomposition(true);
					geom.foreach(function(g:GeomPoly):Void {
						b.shapes.add(new Polygon(g));
						g.clear();
					});
					geom.clear();
					p.clear();
					b.compound=compound;
				});
				polys.clear();
			}
		}
	}

	public function explode(shape:DisplayObject,pos:Vec2):Void {
		data.draw(shape,new Matrix(1,0,0,1,pos.x,pos.y),null,BlendMode.ERASE);
		iso.bounds=AABB.fromRect(shape.getBounds(shape.parent));
		iso.bounds.x+=pos.x;
		iso.bounds.y+=pos.y;
		create();
	}
	public function dispose():Void {
		bitmap = null;
		data.dispose();
		data = null;
		compound.bodies.clear();
		compound.space = null;
		compound = null;
		cells = null;
		cellBounds = null;
		iso.dispose();
		iso = null;
	}
	function get_texture():Bitmap {
		if (bitmap == null) {
			bitmap = new Bitmap(data);
		}
		return bitmap;
	}
	public var texture(get, never):Bitmap;
	function set_space(value:Space):Space {
		return compound.space = value;
	}
	function get_space():Space {
		return compound.space;
	}
	public var space(get,set):Space;
}
